import json
import logging
from datetime import datetime, timedelta
import openai
import pandas as pd
import matplotlib.pyplot as plt
import networkx as nx
import os

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class LearningPlanGenerator:
    """学习计划生成类"""
    
    def __init__(self, config):
        self.config = config
        openai.api_key = self.config["openai_api_key"]
        openai.base_url = self.config.get("openai_base_url", "https://api.openai.com/v1/")
        
        # 常用学习资源库
        self.learning_resources = {
            "编程": ["Coursera", "edX", "Udacity", "LeetCode", "GitHub"],
            "数据分析": ["Kaggle", "DataCamp", "Coursera", "edX", "Analytics Vidhya"],
            "机器学习": ["Coursera-吴恩达课程", "Fast.ai", "TensorFlow官方教程", "Kaggle", "PyTorch教程"],
            "云计算": ["AWS培训", "Google Cloud培训", "Azure学习路径", "A Cloud Guru", "Coursera"],
            "产品管理": ["Coursera", "产品经理社区", "Medium", "Udemy", "Product School"],
            "设计": ["Dribbble", "Behance", "Udemy", "DesignLab", "Skillshare"],
            "营销": ["HubSpot Academy", "Google数字营销", "Coursera", "edX", "Udemy"],
            "项目管理": ["PMI", "Coursera", "edX", "Udemy", "LinkedIn Learning"],
            "软技能": ["LinkedIn Learning", "Coursera", "edX", "Udemy", "Skillshare"]
        }
    
    def generate_learning_plan(self, match_analysis, career_goals="", timeline_months=3):
        """根据技能差距和职业目标生成学习计划
        
        Args:
            match_analysis (dict): 技能匹配分析结果
            career_goals (str): 职业目标描述
            timeline_months (int): 计划时间线（月）
            
        Returns:
            dict: 包含学习计划的字典
        """
        try:
            # 初始化默认返回结构
            default_plan = {
                "skills_plan": [],
                "timeline": timeline_months,
                "resources": [],
                "milestones": []
            }
            
            # 检查入参
            if not match_analysis or not isinstance(match_analysis, dict):
                logger.warning("match_analysis为空或不是字典类型")
                return default_plan
            
            # 输出调试信息
            logger.info(f"match_analysis类型: {type(match_analysis)}")
            logger.info(f"match_analysis包含的键: {match_analysis.keys() if isinstance(match_analysis, dict) else 'N/A'}")
            
            # 提取需要提升的技能
            skills_to_improve = []
            match_details = match_analysis.get('match_analysis', {})
            
            if not match_details:
                logger.warning("没有找到match_analysis.match_analysis字段")
                return default_plan
            
            # 找出匹配度低于90%的技能
            for skill, data in match_details.items():
                if isinstance(data, dict) and 'match_percentage' in data:
                    match_percentage = data['match_percentage']
                    if isinstance(match_percentage, (int, float)) and match_percentage < 90:
                        skills_to_improve.append({
                            "skill": skill,
                            "current_level": data.get('user_level', 0),
                            "target_level": data.get('job_requirement', 0),
                            "priority": "高" if match_percentage < 70 else "中"
                        })
            
            if not skills_to_improve:
                logger.warning("没有需要提升的技能")
                # 即使没有技能需要提升，也生成一个鼓励性的计划
                default_plan["skills_plan"] = [{
                    "skill": "职业通用能力",
                    "current_level": 80,
                    "target_level": 90,
                    "priority": "中",
                    "activities": ["参加行业交流会", "阅读最新技术博客", "学习项目管理知识"]
                }]
                return default_plan
            
            # 按优先级排序
            priority_map = {'高': 3, '中': 2, '低': 1}
            skills_to_improve.sort(key=lambda x: priority_map.get(x.get('priority', '低'), 0), reverse=True)
            
            # 限制技能数量（最多处理前5个）
            skills_to_improve = skills_to_improve[:5]
            
            # 生成学习计划
            learning_plan = {
                'plan_id': f"plan_{datetime.now().strftime('%Y%m%d%H%M%S')}",
                'created_at': datetime.now().strftime('%Y-%m-%d'),
                'timeline_months': timeline_months,
                'career_goals': career_goals,
                'skills_plan': self._generate_skills_plan(skills_to_improve, timeline_months),
                'weekly_schedule': self._generate_weekly_schedule(skills_to_improve),
                'resources': self._recommend_resources(skills_to_improve),
                'milestones': self._generate_milestones(skills_to_improve, timeline_months)
            }
            
            return learning_plan
            
        except Exception as e:
            logger.error(f"学习计划生成错误: {str(e)}")
            return default_plan
    
    def _generate_skills_plan(self, skills_to_improve, timeline_months):
        """生成技能学习计划
        
        Args:
            skills_to_improve (list): 需要提升的技能列表
            timeline_months (int): 学习计划时长(月)
            
        Returns:
            dict: 技能学习计划
        """
        # 定义优先级映射
        priority_map = {
            '高': 3,
            '中': 2,
            '低': 1
        }
        
        # 计算总优先级
        total_priority = sum(priority_map.get(skill.get('priority', '低'), 1) for skill in skills_to_improve)
        
        # 分配学习时间
        skills_plan = []
        for skill in skills_to_improve:
            skill_priority = priority_map.get(skill.get('priority', '低'), 1)
            # 根据优先级分配学习时间比例
            time_allocation = (skill_priority / total_priority) * timeline_months
            
            # 为每个技能创建计划
            skill_plan = {
                'skill_name': skill['skill'],
                'priority': skill.get('priority', '低'),
                'months_allocated': round(time_allocation, 1),
                'current_level': skill.get('current_level', 0),
                'target_level': skill.get('target_level', 0),
                'improvement_focus': skill.get('improvement_focus', [])
            }
            skills_plan.append(skill_plan)
        
        return {
            'total_months': timeline_months,
            'skills': skills_plan
        }
    
    def _generate_learning_path(self, skill, current_level, target_level, weeks):
        """生成技能学习路径"""
        try:
            # 准备生成提示
            resources = self._get_relevant_resources(skill)
            resources_str = ", ".join(resources[:5])
            
            prompt = f"""
            请为提升以下技能设计一个{weeks}周的详细学习路径：
            
            技能: {skill}
            当前水平: {current_level}/100
            目标水平: {target_level}/100
            推荐资源: {resources_str}
            
            学习路径应包含：
            1. 每周学习主题和目标
            2. 推荐的学习资源（课程、文档、实践项目）
            3. 阶段性检验点
            
            以JSON格式返回，示例结构如下：
            {{
                "weekly_plan": [
                    {{
                        "week": 1,
                        "topic": "主题描述",
                        "goals": ["目标1", "目标2"],
                        "resources": ["资源1", "资源2"],
                        "projects": ["项目1"]
                    }},
                    ...
                ]
            }}
            
            请确保所有内容都使用中文回答，不要使用英文。
            """
            
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一位专业的学习规划专家，擅长设计个性化技能提升方案。请使用中文回答。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.5,
                response_format={"type": "json_object"}
            )
            
            result = json.loads(response.choices[0].message.content)
            return result.get('weekly_plan', [])
            
        except Exception as e:
            logger.error(f"学习路径生成错误: {str(e)}")
            # 生成简单的备选方案
            return self._generate_simple_learning_path(skill, weeks)
    
    def _generate_simple_learning_path(self, skill, weeks):
        """生成简单的学习路径（备选方案）"""
        simple_path = []
        
        # 简单划分为入门、进阶和实战三个阶段
        phases = ["入门基础", "进阶学习", "实战项目"]
        
        # 根据周数分配各阶段
        if weeks <= 3:
            phase_weeks = [1, 1, 1]
        else:
            base_weeks = weeks // 3
            phase_weeks = [base_weeks, base_weeks, weeks - 2 * base_weeks]
            
        # 累计周数
        current_week = 1
        
        # 生成各阶段学习计划
        for i, phase in enumerate(phases):
            phase_duration = phase_weeks[i]
            
            for w in range(phase_duration):
                week_plan = {
                    "week": current_week,
                    "topic": f"{phase} - 第{w+1}周",
                    "goals": [f"掌握{skill}的{phase}知识"],
                    "resources": [f"{r}上的{skill}课程" for r in self._get_relevant_resources(skill)[:2]],
                    "projects": [f"{skill}{phase}小项目"]
                }
                simple_path.append(week_plan)
                current_week += 1
                
        return simple_path
    
    def _get_relevant_resources(self, skill):
        """获取与技能相关的学习资源"""
        # 基于技能关键词匹配资源类别
        matched_category = None
        for category, resources in self.learning_resources.items():
            if category.lower() in skill.lower():
                matched_category = category
                break
                
        # 如果没有匹配，使用通用类别
        if not matched_category:
            # 尝试匹配一些常见技能类别
            if any(kw in skill.lower() for kw in ["编程", "开发", "代码", "python", "java", "c++"]):
                matched_category = "编程"
            elif any(kw in skill.lower() for kw in ["数据", "分析", "统计", "报表"]):
                matched_category = "数据分析"
            elif any(kw in skill.lower() for kw in ["机器学习", "深度学习", "ai", "人工智能"]):
                matched_category = "机器学习"
            elif any(kw in skill.lower() for kw in ["云", "aws", "azure", "容器"]):
                matched_category = "云计算"
            elif any(kw in skill.lower() for kw in ["产品", "需求", "用户"]):
                matched_category = "产品管理"
            elif any(kw in skill.lower() for kw in ["设计", "用户体验", "ui", "ux"]):
                matched_category = "设计"
            elif any(kw in skill.lower() for kw in ["营销", "市场", "推广"]):
                matched_category = "营销"
            elif any(kw in skill.lower() for kw in ["项目", "管理", "敏捷", "scrum"]):
                matched_category = "项目管理"
            else:
                matched_category = "软技能"  # 默认类别
                
        # 返回匹配类别的资源
        return self.learning_resources.get(matched_category, ["Coursera", "Udemy", "YouTube教程"])
    
    def _generate_weekly_schedule(self, skills_to_improve):
        """生成每周学习时间安排"""
        # 假设每周有20小时可用于学习
        total_hours = 20
        weekly_schedule = {}
        
        # 按优先级分配学习时间
        priority_map = {'高': 3, '中': 2, '低': 1}
        total_priority = sum(priority_map.get(skill.get('priority', '低'), 1) for skill in skills_to_improve)
        
        for skill_data in skills_to_improve:
            skill = skill_data.get('skill', '')
            priority = skill_data.get('priority', '低')
            
            # 分配学习时间（基于优先级）
            priority_value = priority_map.get(priority, 1)
            hours_allocation = max(2, int((priority_value / total_priority) * total_hours))
            
            # 安排每天学习时间
            daily_hours = self._distribute_hours(hours_allocation)
            
            weekly_schedule[skill] = {
                'total_hours': hours_allocation,
                'daily_distribution': daily_hours
            }
            
        return weekly_schedule
    
    def _distribute_hours(self, total_hours):
        """将总学习时间分配到每天"""
        # 简单策略：周一到周五每天平均分配，周末多一些
        daily_hours = [0] * 7  # 周一到周日
        
        if total_hours <= 7:
            # 时间很少，每天安排1小时或隔天安排
            for i in range(total_hours):
                daily_hours[i] = 1
        else:
            # 周一到周五平均分配约60%的时间
            weekday_hours = int(total_hours * 0.6)
            for i in range(5):
                daily_hours[i] = weekday_hours // 5
                
            # 剩余时间分配到周末
            weekend_hours = total_hours - sum(daily_hours)
            daily_hours[5] = weekend_hours // 2
            daily_hours[6] = weekend_hours - daily_hours[5]
            
        return daily_hours
    
    def _recommend_resources(self, skills_to_improve):
        """推荐学习资源"""
        resources = {}
        
        for skill_data in skills_to_improve:
            skill = skill_data.get('skill', '')
            
            # 获取与技能相关的资源
            skill_resources = self._get_detailed_resources(skill)
            
            resources[skill] = skill_resources
            
        return resources
    
    def _get_detailed_resources(self, skill):
        """获取详细的学习资源推荐"""
        try:
            # 获取基础资源类别
            base_resources = self._get_relevant_resources(skill)
            
            # 使用LLM生成更详细的资源推荐
            prompt = f"""
            请为学习"{skill}"技能推荐5个具体的学习资源，包括：
            
            1. 2-3个在线课程（免费或付费均可，提供具体课程名和平台）
            2. 1-2个实战项目（适合提升该技能的实践项目）
            3. 1-2个参考书籍或文档
            
            以JSON格式返回，包含以下三个分类：
            {{
                "courses": [
                    {{"name": "课程名称", "platform": "平台名称"}},
                    // 更多课程...
                ],
                "projects": [
                    {{"name": "项目名称", "description": "项目描述"}},
                    // 更多项目...
                ],
                "references": [
                    {{"name": "参考资料名称", "type": "资料类型"}},
                    // 更多参考资料...
                ]
            }}
            
            请确保所有内容都使用中文回答，不要使用英文。
            """
            
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一位教育资源专家，擅长推荐高质量的学习资源。请使用中文回答。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.5,
                response_format={"type": "json_object"}
            )
            
            result = json.loads(response.choices[0].message.content)
            
            return result
            
        except Exception as e:
            logger.error(f"资源推荐错误: {str(e)}")
            
            # 生成简单的备选方案
            return {
                "courses": [
                    {"name": f"{skill}基础课程", "platform": "慕课网"},
                    {"name": f"{skill}进阶教程", "platform": "中国大学MOOC"}
                ],
                "projects": [
                    {"name": f"{skill}实战项目", "description": "通过实践提升技能"}
                ],
                "references": [
                    {"name": f"{skill}入门指南", "type": "在线文档"}
                ]
            }
    
    def _generate_milestones(self, skills_to_improve, timeline_months):
        """生成学习里程碑"""
        milestones = []
        
        # 设置几个关键时间点
        checkpoints = [
            {"month": 0, "name": "起点评估", "description": "记录当前技能水平"},
            {"month": timeline_months // 3, "name": "初期检查点", "description": "评估前期学习成果"},
            {"month": timeline_months * 2 // 3, "name": "中期检查点", "description": "评估中期学习进展"},
            {"month": timeline_months, "name": "最终评估", "description": "综合评估所有技能提升情况"}
        ]
        
        # 生成基础里程碑
        start_date = datetime.now()
        
        for checkpoint in checkpoints:
            milestone_date = start_date + timedelta(days=checkpoint["month"] * 30)
            
            milestone = {
                "date": milestone_date.strftime('%Y-%m-%d'),
                "name": checkpoint["name"],
                "description": checkpoint["description"],
                "skills_check": []
            }
            
            # 添加技能检查点
            for skill_data in skills_to_improve:
                skill = skill_data.get('skill', '')
                current_level = skill_data.get('current_level', 0)
                target_level = skill_data.get('target_level', 70)
                
                # 计算预期进度
                progress_ratio = checkpoint["month"] / timeline_months
                expected_level = int(current_level + (target_level - current_level) * progress_ratio)
                
                skill_check = {
                    "skill": skill,
                    "expected_level": expected_level,
                    "validation_method": self._get_validation_method(skill)
                }
                
                milestone["skills_check"].append(skill_check)
                
            milestones.append(milestone)
            
        return milestones
    
    def _get_validation_method(self, skill):
        """获取技能验证方法"""
        # 根据技能类型返回不同的验证方法
        if any(kw in skill.lower() for kw in ["编程", "开发", "代码", "python", "java", "c++"]):
            return "完成编程挑战或小项目"
        elif any(kw in skill.lower() for kw in ["数据", "分析", "统计"]):
            return "完成数据分析案例，形成分析报告"
        elif any(kw in skill.lower() for kw in ["机器学习", "深度学习", "ai"]):
            return "构建并评估机器学习模型"
        elif any(kw in skill.lower() for kw in ["设计", "用户体验", "ui", "ux"]):
            return "完成设计作品集"
        else:
            return "完成评估测试或项目实践"
            
    def visualize_learning_plan(self, learning_plan, output_path=None):
        """可视化学习计划
        
        Args:
            learning_plan (dict): 学习计划
            output_path (str, optional): 输出路径
            
        Returns:
            str: 图表保存路径
        """
        try:
            # 设置中文字体
            plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'SimSun', 'Arial Unicode MS', 'DejaVu Sans']
            plt.rcParams['axes.unicode_minus'] = False
            
            # 获取技能计划
            if not isinstance(learning_plan, dict):
                logger.error(f"学习计划应为字典类型，而不是 {type(learning_plan)}")
                return None
            
            skills_plan = learning_plan.get('skills_plan', {})
            if not isinstance(skills_plan, dict):
                logger.error(f"skills_plan应为字典类型，而不是 {type(skills_plan)}")
                return None
            
            skills = skills_plan.get('skills', [])
            if not isinstance(skills, list):
                logger.error(f"skills应为列表类型，而不是 {type(skills)}")
                return None
            
            if not skills:
                logger.warning("学习计划中没有技能数据可视化")
                return None
            
            # 提取数据
            skill_names = []
            months_allocated = []
            priorities = []
            
            for skill in skills:
                if not isinstance(skill, dict):
                    logger.warning(f"跳过非字典类型的技能项: {skill}")
                    continue
                    
                skill_name = skill.get('skill_name', '')
                months = skill.get('months_allocated', 0)
                priority = skill.get('priority', '低')
                
                skill_names.append(skill_name)
                months_allocated.append(months)
                priorities.append(priority)
            
            # 创建图表 - 调整图表大小以解决布局问题
            fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))  # 增加图表尺寸
            
            # 左侧：时间分配条形图
            colors = ['#ff9999' if p == '高' else '#66b3ff' if p == '中' else '#99ff99' for p in priorities]
            ax1.barh(skill_names, months_allocated, color=colors)
            ax1.set_xlabel('分配时间 (月)')
            ax1.set_title('技能学习时间分配')
            ax1.grid(axis='x', linestyle='--', alpha=0.7)
            
            # 右侧：学习计划时间线
            ax2.axis('off')
            ax2.set_title('学习计划时间轴')
            
            total_months = learning_plan.get('skills_plan', {}).get('total_months', sum(months_allocated))
            
            # 绘制时间轴
            ax2.axhline(y=0.5, xmin=0.05, xmax=0.95, color='gray', alpha=0.3)
            
            # 添加开始和结束点
            ax2.scatter([0.05, 0.95], [0.5, 0.5], color='gray', s=100, zorder=5)
            ax2.annotate('开始', (0.05, 0.5), xytext=(0.05, 0.55),
                        ha='center', va='bottom', fontsize=10)
            ax2.annotate(f'{total_months}个月后', (0.95, 0.5), xytext=(0.95, 0.55),
                        ha='center', va='bottom', fontsize=10)
            
            # 添加技能里程碑
            current_point = 0.05
            for i, (skill, months) in enumerate(zip(skill_names, months_allocated)):
                position = current_point + (months / total_months) * 0.9 * 0.5
                current_point = position
                
                ax2.scatter([position], [0.5], color=colors[i], s=150, zorder=10)
                
                if i % 2 == 0:
                    ax2.annotate(skill, (position, 0.5), xytext=(position, 0.4),
                                ha='center', va='top', fontsize=9,
                                arrowprops=dict(arrowstyle='->', color='black', alpha=0.7))
                else:
                    ax2.annotate(skill, (position, 0.5), xytext=(position, 0.6),
                                ha='center', va='bottom', fontsize=9,
                                arrowprops=dict(arrowstyle='->', color='black', alpha=0.7))
            
            # 手动调整子图边距，而不是使用tight_layout
            fig.subplots_adjust(left=0.1, right=0.95, top=0.9, bottom=0.15, wspace=0.3)
            
            # 保存图表
            if not output_path:
                timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
                output_path = f"data/learning_plan_viz_{timestamp}.png"
            
            # 确保目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            plt.savefig(output_path, dpi=300, bbox_inches='tight')
            plt.close(fig)
            
            logger.info(f"学习计划可视化已保存至: {output_path}")
            return output_path
            
        except Exception as e:
            logger.error(f"学习计划可视化错误: {str(e)}")
            return None
        
    def generate_plan_summary(self, learning_plan):
        """生成学习计划摘要
        
        Args:
            learning_plan (dict): 学习计划
            
        Returns:
            str: 计划摘要
        """
        try:
            # 提取关键信息
            skills_plan = learning_plan.get('skills_plan', [])
            timeline = learning_plan.get('timeline_months', 3)
            goals = learning_plan.get('career_goals', '')
            
            # 使用LLM生成摘要
            skills_json = json.dumps(skills_plan, ensure_ascii=False)
            
            prompt = f"""
            请根据以下学习计划信息，生成一份简洁的学习计划摘要（不超过300字）：
            
            职业目标: {goals}
            时间周期: {timeline}个月
            
            技能计划: {skills_json}
            
            摘要应包含：
            1. 计划概述
            2. 重点技能和优先级
            3. 预期成果
            4. 鼓励性话语
            
            请确保使用中文回答，给出结构清晰的摘要。
            """
            
            response = openai.chat.completions.create(
                model=self.config["llm_model"],
                messages=[
                    {"role": "system", "content": "你是一位学习规划顾问，擅长简明扼要地总结学习计划。请使用中文回答。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
                max_tokens=500
            )
            
            return response.choices[0].message.content.strip()
            
        except Exception as e:
            logger.error(f"计划摘要生成错误: {str(e)}")
            
            # 生成简单摘要
            skills = [plan['skill'] for plan in learning_plan.get('skills_plan', [])]
            skills_str = "、".join(skills)
            
            return f"""
            ## 学习计划摘要
            
            本计划将在{learning_plan.get('timeline_months', 3)}个月内提升{len(skills)}项关键技能：{skills_str}。
            
            根据技能优先级和当前水平，制定了每周学习目标和资源推荐。通过坚持执行计划，
            预计可以显著提升技能匹配度，为职业发展打下坚实基础。
            
            坚持学习，定期复盘，相信你一定能够实现目标！
            """ 